﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using NUnit.Framework;

namespace Wix.Aura.UnitTests.Tools {
	public static class XmlAssert {
		public static void AreEqual<T>(string expected, T actual) {
			AreEqual(XElement.Parse(expected), actual);
		}

		public static void AreEqual<T>(XElement expected, T actual) {
			AreEqual(expected, Serialize(actual));
		}

		public static void AreEqual(XElement expected, XElement actual) {
			Assert.AreEqual(Normalize(expected).ToString(), Normalize(actual).ToString());
		}

		private static XElement Normalize(XElement element) {
			if (element.HasElements) {
				return new XElement(element.Name, element.Attributes().OrderBy(a => a.Name.ToString()), element.Elements().OrderBy(a => a.Name.ToString()).Select(e => Normalize(e)));
			}

			if (element.IsEmpty) {
				return new XElement(element.Name, element.Attributes().OrderBy(a => a.Name.ToString()));
			}

			return new XElement(element.Name, element.Attributes().OrderBy(a => a.Name.ToString()), element.Value);
		}

		private static void Serialize<T>(XmlWriter stream, T serializable) {
			XmlSerializer serializer = new XmlSerializer(typeof(T));
			using (XmlWriter writer = XmlTextWriter.Create(stream)) {
				serializer.Serialize(writer, serializable);
			}
		}

		private static XElement Serialize<T>(T serializable) {
			XDocument doc = new XDocument();

			Serialize(doc.CreateWriter(), serializable);
			return doc.Elements().First().Elements().First();
		}
	}
}
